import {
    ApplicationConfigAndExecutorImpl,
    ApplicationImpl,
    Group,
    GroupName,
    Platform,
    ProjectItemImpl,
    SettingItem,
    ShellExecutor,
    SwitchSettingItem,
} from '../../Types'
import {execFileSync} from 'child_process'
import {isEmpty, isNil, startWith, unique, Url} from 'licia'
import {parse} from 'path'
import {existsOrNot, generateSearchKeyWithPinyin, generateStringByOS} from '../../Utils'
import {Context} from '../../Context'
import {i18n, sentenceKey} from '../../i18n'

const VSCODE: string = 'vscode'

export class VscodeProjectItemImpl extends ProjectItemImpl {}

export class VscodeApplicationImpl extends ApplicationConfigAndExecutorImpl<VscodeProjectItemImpl> {
    openInNew: boolean = false
    private isWindows: boolean = utools.isWindows()

    constructor() {
        super(
            VSCODE,
            'Visual Studio Code',
            'icon/ms-visual-studio-code.png',
            VSCODE,
            [Platform.win32, Platform.darwin, Platform.linux],
            Group[GroupName.editor],
            () => `${i18n.t(sentenceKey.configFileAt)} ${generateStringByOS({
                win32: 'C:\\Users\\xxxx\\AppData\\Roaming\\Code\\User\\globalStorage\\state.vscdb',
                darwin: '/Users/xxxx/Library/Application Support/Code/User/globalStorage/state.vscdb',
                linux: '/home/xxxx/.config/Code/User/globalStorage/state.vscdb',
            })}, ${i18n.t(sentenceKey.executorFileAt)} ${generateStringByOS({
                win32: 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe',
                darwin: '/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code',
                linux: '(不同发行版安装路径差异较大, 自行使用 which 命令找到 code 命令所在路径作为可执行文件路径)',
            })}`,
            undefined,
            'state.vscdb',
        )
    }

    async generateProjectItems(context: Context): Promise<Array<VscodeProjectItemImpl>> {
        let result = execFileSync('sqlite3', [this.config, "select value from ItemTable where key='history.recentlyOpenedPathsList'", '-readonly'], { encoding: 'utf-8', maxBuffer: 20971520 })
        if (!result) {
            return []
        }

        let storage = JSON.parse(result)
        let entries = storage?.entries
        if (isNil(entries)) {
            return []
        }

        const getIcon = context.enableGetFileIcon ? utools.getFileIcon : () => this.icon
        const args = this.openInNew ? '-n' : ''
        return entries.filter(element => {
            element['uri'] = this.getUri(element)
            return !isEmpty(element['uri'])
        }).map(element => {
            const uri = element['uri']
            const uriParsed = decodeURIComponent(uri)
            const urlParsed = Url.parse(uriParsed)
            let path = urlParsed.pathname
            if (this.isWindows) {
                path = path.substring(1)
            }
            let { exists, description, icon } = existsOrNot(path, {
                description: path,
                icon: getIcon(path),
            })

            let commandText = `"${this.executor}" ${args} "${path}"`

            // 对 remote folder 进行处理
            if (startWith(uri, 'vscode-remote')) {
                let label = element['label'] ?? uriParsed
                exists = true
                description = label
                commandText = `"${this.executor}" --folder-uri "${uriParsed}"`
            }

            const parseObj = parse(path)
            return {
                id: '',
                title: parseObj.name,
                description: description,
                icon: icon,
                searchKey: unique([...generateSearchKeyWithPinyin(parseObj.name), parseObj.name + (parseObj.ext ? parseObj.ext : '')]),
                exists: exists,
                command: new ShellExecutor(commandText),
            }
        })
    }

    openInNewId(nativeId: string) {
        return `${nativeId}/${this.id}-open-in-new`
    }

    override update(nativeId: string) {
        super.update(nativeId)
        this.openInNew = utools.dbStorage.getItem(this.openInNewId(nativeId)) ?? false
    }

    override generateSettingItems(context: Context, nativeId: string): Array<SettingItem> {
        let superSettings = super.generateSettingItems(context, nativeId)
        superSettings.splice(1, 0, new SwitchSettingItem(
            this.openInNewId(nativeId),
            i18n.t(sentenceKey.openInNew),
            this.openInNew,
            i18n.t(sentenceKey.openInNewDesc),
        ))
        return superSettings
    }

    private getUri(entry: any): string {
        const folderUri = entry['folderUri'],
              fileUri = entry['fileUri'],
              workspace = entry['workspace']
        if (!isEmpty(folderUri)) {
            return folderUri
        }
        if (!isEmpty(fileUri)) {
            return fileUri
        }
        if (!isNil(workspace)) {
            return workspace['configPath']
        }
        return ''
    }
}

export const applications: Array<ApplicationImpl<VscodeProjectItemImpl>> = [
    new VscodeApplicationImpl(),
]
